import React, {
  memo,
  forwardRef,
  useState,
  useRef,
  useEffect,
  useImperativeHandle,
  useMemo,
} from 'react';
import PropTypes from 'prop-types';
import BScroll from '@better-scroll/core';
import styled from 'styled-components';
import Loading from '../loading';
import Loading2 from '../loading-v2/';
import { debounce } from '@/api/utils';

const ScrollContainer = styled.div`
  width: 100%;
  height: 100%;
  overflow: hidden;
`;
const PullUpLoading = styled.div`
  position: absolute;
  left: 0;
  right: 0;
  bottom: 5px;
  width: 60px;
  height: 60px;
  margin: auto;
  z-index: 100;
`;
export const PullDownLoading = styled.div`
  position: absolute;
  left: 0;
  right: 0;
  top: 0px;
  height: 30px;
  margin: auto;
  z-index: 100;
`;
// forwardRef 可以让绑定ref
const Scroll = memo(
  forwardRef((props, ref) => {
    // better-scroll 实例对象
    const [bScroll, setBScroll] = useState();
    // current 指向初始化bs实例对象需要的DOM元素
    const scrollContainerRef = useRef();
    const {
      direction,
      click,
      refresh,
      pullUpLoading,
      pullDownLoading,
      bounceTop,
      bounceBottom,
      pullUp,
      pullDown,
      onScroll,
    } = props;
    const pullUpDebounce = useMemo(() => {
      return debounce(pullUp, 400);
    }, [pullUp]);
    const pullDownDebounce = useMemo(() => {
      return debounce(pullDown, 400);
    }, [pullDown]);
    //afterRender 创建better-scroll
    useEffect(() => {
      const scroll = new BScroll(scrollContainerRef.current, {
        scrollX: direction === 'horizontal',
        scrollY: direction === 'vertical',
        probeType: 3,
        click: click,
        bounce: {
          top: bounceTop,
          bottom: bounceBottom,
        },
      });
      setBScroll(scroll);
      return () => {
        setBScroll(null);
      };
      //eslint-disable-next-line
    }, []);
    // 每次重新渲染都要刷新实例，防止无法滑动
    useEffect(() => {
      if (refresh && bScroll) {
        bScroll.refresh();
      }
    });
    // 给scroll实例绑定事件, 滑动事件
    useEffect(() => {
      //  bScroll是否创建实例 是否传入onScroll
      if (!bScroll || !onScroll) return;
      bScroll.on('scroll', (scroll) => {
        onScroll(scroll);
      });
      return () => {
        bScroll.off('scroll');
      };
    }, [onScroll, bScroll]);
    // 进行上拉到底的判断，调用上拉刷新的函数
    useEffect(() => {
      if (!bScroll || !pullUp) return;
      bScroll.on('scrollEnd', () => {
        // 判断是否滑动到底部
        if (bScroll.y <= bScroll.maxScrollY + 100) {
          pullUpDebounce();
        }
      });
      return () => {
        bScroll.off('scrollEnd');
      };
    }, [pullUpDebounce, pullUp, bScroll]);
    // 进行下拉的判断，调用下拉刷新的函数
    useEffect(() => {
      if (!bScroll || !pullDown) return;
      bScroll.on('touchEnd', (pos) => {
        //判断用户的下拉动作
        if (pos.y > 50) {
          pullDownDebounce();
        }
      });
      return () => {
        bScroll.off('touchEnd');
      };
    }, [pullDown, pullDownDebounce, bScroll]);
    // 对ref进行设置，让外界只能访问到 refresh和getbScroll
    useImperativeHandle(ref, () => ({
      refresh() {
        if (bScroll) {
          bScroll.refresh();
          bScroll.scrollTo(0, 0);
        }
      },
      getBScroll() {
        if (bScroll) {
          return bScroll;
        }
      },
    }));
    const PullUpdisplayStyle = pullUpLoading
      ? { display: '' }
      : { display: 'none' };
    const PullDowndisplayStyle = pullDownLoading
      ? { display: '' }
      : { display: 'none' };

    return (
      // 相当于wrapper
      <ScrollContainer ref={scrollContainerRef}>
        {/* 相当于content  */}
        {props.children}

        {/* 滑到底部加载动画 */}
        <PullUpLoading style={PullUpdisplayStyle}>
          <Loading></Loading>
        </PullUpLoading>
        {/* 顶部下拉刷新动画 */}
        <PullDownLoading style={PullDowndisplayStyle}>
          <Loading2></Loading2>
        </PullDownLoading>
      </ScrollContainer>
    );
  })
);
Scroll.propTypes = {
  direction: PropTypes.oneOf(['vertical', 'horizontal']), //滚动的方向
  click: PropTypes.bool, //是否支持点击
  refresh: PropTypes.bool, //是否刷新
  onScroll: PropTypes.func, //滑动触发的回掉函数
  pullUp: PropTypes.func, // 上拉加载逻辑
  pullDown: PropTypes.func, //下拉加载逻辑
  pullUpLoading: PropTypes.bool, //是否显示上拉loading动画
  pullDownLoading: PropTypes.bool, //是否显示下拉loading动画
  bounceTop: PropTypes.bool, // 是否支持向上吸顶
  bounceBottom: PropTypes.bool, // 是否支持向下吸底
};
Scroll.defaultProps = {
  direction: 'vertical',
  click: true,
  refresh: true,
  onScroll: null,
  pullUpLoading: false,
  pullDownLoading: false,
  pullUp: () => {
    console.log('pullUp');
  },
  pullDown: () => {
    console.log('pulldown');
  },
  bounceTop: true,
  bounceBottom: true,
};
export default Scroll;
